home *** CD-ROM | disk | FTP | other *** search
/ Shareware Grab Bag / Shareware Grab Bag.iso / 050 / madtrb13.arc / TERMINAL.PAS < prev    next >
Pascal/Delphi Source File  |  1985-05-19  |  42KB  |  1,302 lines

  1.  
  2. {$C-}
  3. {$V-}
  4.  
  5. program terminal;  {This is a terminal handling package by Jim Nutt
  6.                     CIS - 71076,1434 or EIS - 76044,1155.
  7.                     It is public domain and not to be sold
  8.                     vidtex compatible
  9.                     CIS-A file transfers}
  10.  
  11. {$u-}  {Serial I/O drivers start here}
  12.  
  13. Const
  14.      RECV_BUF_SIZE = 4096;             {this may be changed to
  15.                                         whatever size you need}
  16.     DEFAULT_BAUD   =  300;
  17. { *** Port addresses *** }
  18.      THR = $3F8;                       {Transmitter Holding Register: the
  19.                                         serial port address we use to send
  20.                                         data}
  21.      IER = $3F9;                       {Interrupt Enable Register for the
  22.                                         serial port}
  23.      LCR = $3FB;                       {Line Control Register for the serial
  24.                                         port. Determines data bits, stop bits
  25.                                         and parity, contributes to setting
  26.                                         baud-rate}
  27.      MCR = $3FC;                       {Modem Control Register}
  28.      LSR = $3FD;                       {Line Status Register}
  29.      MSR = $3FE;                       {Modem Status Register}
  30.      IMR = $021;                       {Interrupt Mask Register port address
  31.                                         of Intel 8259A Programmable Interrupt
  32.                                         controller}
  33. { *** Masks *** }
  34.      ENABLE_OUT2 = 8;                  {Setting bit 3 of MCR enables OUT2}
  35.      ENABLE_DAV = 1;                   {Setting bit 0 of IER enables Data
  36.                                         AVailable interrupt from serial port}
  37.      ENABLE_IRQ4 = $EF;                {Clearing bit 5 of IMR enables serial
  38.                                         interrupts to reach the CPU}
  39.      DISABLE_OUT2 = 1;                 {Clearing MCR disables OUT2}
  40.      DISABLE_DAV = 0;                  {Clearing IER disables Data
  41.                                        AVailable interrupt from serial port}
  42.      DISABLE_IRQ4 = $10;               {Setting bit 5 of IMR stops serial
  43.                                         interrupts from reaching the CPU}
  44.      SET_BAUD = $80;                   {Setting bit 7 of LCR allows us to set
  45.                                         the baud rate of the serial port}
  46.      SET_PARMS = $7F;                  {Clearing bit 7 of LCR allows us to set
  47.                                         non-baud-rate parameters on the
  48.                                         serial port}
  49.  
  50. Type
  51.     parity_set        = (none,even);    {readability and expansion}
  52.     bigstring        = string[80];
  53.  
  54. Var
  55.    buf_start, buf_end    : integer;    {NOTE: these will change by them-
  56.                                         selves in the background}
  57.    recv_buffer           : array [1..RECV_BUF_SIZE] of byte;
  58.                                        {also self-changing}
  59.    speed                 : integer;    {I don't know the top speed these
  60.                                         routines will handle}
  61.    dbits                 : 7..8;       {only ones most people use}
  62.    stop_bits             : 1..2;       {does anyone use 2?}
  63.    parity                : parity_set;  {even and none are the common ones}
  64.  
  65. function cgetc(TimeLimit : integer) : integer;
  66. {if a byte is recieved at COM1: in less than TimeLimit seconds,
  67.  returns byte as an integer, else returns -1}
  68.  
  69. const
  70.      TIMED_OUT = -1;
  71. begin
  72.      TimeLimit := TimeLimit shl 10;     {convert TimeLimit to millisecs}
  73.      while (buf_start = buf_end) and (TimeLimit > 0) do
  74.        begin
  75.           delay(1);
  76.           TimeLimit := pred(TimeLimit)
  77.        end;
  78.      if (TimeLimit >= 0) and (buf_start <> buf_end)
  79.        then
  80.          begin
  81.            inline ($FA);            {suspend interrupts}
  82.            cgetc := recv_buffer[buf_start];
  83.            buf_start := succ(buf_start);
  84.            if buf_start > RECV_BUF_SIZE
  85.              then
  86.                buf_start := 1;
  87.            inline ($FB);            {resume interrupts}
  88.          end
  89.        else
  90.          cgetc := TIMED_OUT;
  91. end;
  92.  
  93. procedure send(c : byte);
  94.  
  95. var
  96.    a : byte;
  97. begin
  98.   repeat
  99.        a := port[LSR]
  100.   until odd(a shr 5);
  101.   port[THR] := c;
  102. end;
  103.  
  104. procedure StrSend(s : bigstring);
  105.  
  106. var
  107.    i : integer;
  108. begin
  109.      for i := 1 to length(s) do
  110.          begin
  111.            send(ord(s[i]));
  112.            delay(10);
  113.          end
  114. end;
  115.  
  116. procedure SendPaced(s : bigstring);
  117.  
  118. label
  119.      99;
  120.  
  121. const
  122.      CRSYM = '<';
  123.  
  124. var
  125.    i : integer;
  126.    c : integer;
  127. begin
  128.      for i := 1 to Length(s) do
  129.        begin
  130.           if s[i] = CRSYM
  131.             then
  132.               send(13)
  133.             else
  134.               send(ord(s[i]));
  135.           c := cgetc(1);
  136.           if c <> -1
  137.             then
  138.               write(chr(c))
  139.             else begin
  140.                    sound(440);
  141.                    delay(20);
  142.                    nosound;
  143.                    goto 99
  144.               end
  145.        end;
  146.   99:
  147. end;
  148.  
  149. {Communications routines for TURBO Pascal written by Alan Bishop,
  150.  modified slightly by Scott Murphy.
  151.  Handles standart COM1: ports with interrupt handling.  Includes
  152.  support for only one port, and with no overflow, parity, or other
  153.  such checking.  However, even some of the best communication programs
  154.  don't do this anyway, and I never use it.  If you make modifications,
  155.  please send me a copy if you have a simple way of doing it (CIS EMAIL,
  156.  Usenet, MCI Mail, etc)  Hope these are useful.
  157.  
  158. Alan Bishop - CIS      - 72405,647
  159.               Usenet   - bishop@ecsvax
  160.               MCI Mail - ABISHOP
  161. }
  162.  
  163. procedure update_uart;
  164. {uses dbits, stop_bits, and parity}
  165.  
  166. var
  167.    newparm, oldLCR : byte;
  168. begin
  169.   newparm := dbits-5;
  170.   if stop_bits = 2
  171.     then newparm := newparm + 4;
  172.   if parity = even
  173.     then newparm := newparm + 24;
  174.   oldLCR := port[LCR];
  175.   port[LCR] := oldLCR and SET_PARMS;
  176.   port[LCR] := newparm;
  177. end;
  178.  
  179.  
  180. procedure term_ready(state : boolean);
  181. {if state = TRUE then set RTS true else set false}
  182.  
  183. var
  184.    OldMCR : byte;
  185. begin
  186.      OldMCR := port[MCR];
  187.      if state
  188.        then
  189.          port[MCR] := OldMCR or 1
  190.        else
  191.          port[MCR] := OldMCR and $FE
  192. end;
  193.  
  194. function carrier : boolean;
  195. {true if carrier, false if not}
  196. begin
  197.   carrier := odd(port[MSR] shr 7);
  198. end;
  199.  
  200. procedure set_up_recv_buffer;
  201. begin
  202.   buf_start := 1;
  203.   buf_end   := 1;
  204. end;
  205.  
  206. procedure new_baud(rate : integer);
  207. {has no problems with non-standard bauds}
  208.  
  209. var
  210.    OldLCR : byte;
  211. begin
  212.   if rate <= 9600
  213.     then
  214.       begin
  215.         speed := rate;
  216.         rate := trunc(115200.0/rate);
  217.         OldLCR := port[LCR] or SET_BAUD;
  218.         port[LCR] := OldLCR;
  219.         port[THR] := lo(rate);
  220.         port[IER] := hi(rate);
  221.         port[LCR] := OldLCR and SET_PARMS;
  222.       end;
  223. end;
  224.  
  225. procedure init_port;
  226. {installs interrupt sevice routine for serial port}
  227.  
  228. var a,b : integer;
  229.     buf_len : integer;
  230. begin
  231.   update_uart;
  232.   new_baud(speed);
  233.   buf_len := RECV_BUF_SIZE;
  234.  
  235.  {this is the background routine}
  236.  
  237.   inline (
  238.               $1E/                     {push ds}
  239.               $0E/                     {push cs}
  240.               $1F/                     {pop  ds                  ;ds := cs}
  241.               $BA/*+23/                {mov  dx, offset ISR}
  242.               $B8/$0C/$25/             {mov  ax, 250CH           ;set COM1: vector}
  243.               $CD/$21/                 {int  21H}
  244.               $8B/$BE/BUF_LEN/         {mov  di, buf_len}
  245.               $89/$3E/*+87/            {mov  lcl_buf_len,di}
  246.               $1F/                     {pop  ds}
  247.               $2E/$8C/$1E/*+83/        {mov  lcl_ds, ds}
  248.               $EB/$51/                 {jmp  exit}
  249. {ISR:}        $FB/                     {sti}
  250.               $1E/                     {push ds}
  251.               $50/                     {push ax}
  252.               $53/                     {push bx}
  253.               $52/                     {push dx}
  254.               $56/                     {push si}
  255.               $2E/$8E/$1E/*+70/        {mov  ds,[lcl_ds]}
  256.               $BA/$F8/$03/             {mov  dx, 3F8H           ;address RBR}
  257.               $EC/                     {in   al, dx             ;read rbr}
  258.               $BE/RECV_BUFFER/
  259.           {mov  si, recv_buffer    ;address start of recv_buffer}
  260.               $8B/$1E/BUF_END/
  261.           {mov  bx, [buf_end]      ;index of current char in recv_buffer}
  262.               $88/$40/$FF/             {mov  [bx+si-1],al       ;copy char to recv_buffer}
  263.               $43/                     {inc  bx                 ;update buf_end}
  264.               $E8/$22/$00/             {call adj_idx}
  265.               $89/$1E/BUF_END/         {mov  [buf_end],bx}
  266.               $3B/$1E/BUF_START/       {cmp  bx, [buf_start]}
  267.               $75/$0C/                 {jnz  ISR_DONE}
  268.               $8B/$1E/BUF_START/       {mov  bx,buf_start}
  269.               $43/                     {inc  bx}
  270.               $E8/$10/$00/             {call adj_idx}
  271.               $89/$1E/BUF_START/       {mov  [buf_start],bx}
  272.               $BA/$20/$00/             {mov  dx,20H            ;EOI command for 8259A PIC}
  273.               $B0/$20/                 {mov  al,20H            ;EOI port for 8259A PIC}
  274.               $EE/                     {out  dx,al             ;End Of Interrupt}
  275.               $5E/                     {pop  si}
  276.               $5A/                     {pop  dx}
  277.               $5B/                     {pop  bx}
  278.               $58/                     {pop  ax}
  279.               $1F/                     {pop  ds}
  280.               $CF/                     {iret}
  281. {adj_idx:}    $2E/$8B/$16/*+11/        {mov  dx,[lcl_buf_len]}
  282.               $42/                     {inc  dx}
  283.               $39/$DA/                 {cmp  dx,bx}
  284.               $75/$03/                 {jnz  no_change}
  285.               $BB/$01/$00/             {mov  bx,1}
  286. {no_change:}  $C3/                     {ret}
  287. {lcl_buf_len;}$00/$00/                 {dw  0}
  288.               $00/$01/                 {dw  1}
  289. {exit:}       $90                      {nop}
  290.   );
  291.   port[IER] := ENABLE_DAV;              {interrupt enable}
  292.   a := port[MCR];
  293.   port[MCR] := a or ENABLE_OUT2;        {preserve RTS and enable OUT2}
  294.   a := port[IMR];
  295.   a := a and ENABLE_IRQ4;
  296.   port[IMR]  := a;
  297. end;
  298.  
  299.  
  300. procedure remove_port;
  301. {disables DAV, OUT2 and IRQ4 so that COM1: will no longer be serviced}
  302.  
  303. var
  304.    a : byte;
  305. begin
  306.      a         := port[IMR];
  307.      port[IMR] := a or DISABLE_IRQ4;
  308.      port[IER] := DISABLE_DAV;
  309.      a         := port[MCR];
  310.      port[MCR] := a and DISABLE_OUT2;
  311. end;
  312.  
  313.  
  314. procedure break;
  315. {send a break}
  316.  
  317. var a,b : byte;
  318. begin
  319.   a := port[LCR];
  320.   b := (a and $7F) or $40;
  321.   port[LCR] := b;
  322.   delay(400);
  323.   port[LCR] := a;
  324. end;
  325.  
  326. procedure setup;
  327. {initialize most stuff - you may want to replace this routine completely}
  328. begin
  329.   dbits        := 8;
  330.   parity       := none;
  331.   stop_bits    := 1;
  332.   speed        := DEFAULT_BAUD;
  333.   init_port;
  334.   term_ready(true);
  335. end;
  336. {$u+}
  337.  
  338. const 
  339.   minint = -32767;
  340.  
  341. type 
  342.   buftype = array[0..520] of char;
  343.   bigbuf  = array[minint..maxint] of byte;
  344.   wstr    = string[60];
  345.  
  346. var 
  347.   parms       : wstr;
  348.   tstr        : wstr;
  349.   number      : wstr;
  350.   old_carrier : boolean;
  351.   ch          : char;
  352.   exit        : boolean;
  353.   rcvd        : integer;
  354.   save        : boolean;
  355.   buffer      : ^bigbuf;
  356.   buffptr     : integer;
  357.   i,j         : integer;
  358.   blocks      : integer;
  359.   bytes       : integer;
  360.   total_bytes : real;
  361.   left4       : boolean;
  362.   left1       : boolean;
  363.   left256     : boolean;
  364.   capture     : file;
  365.   filename    : string[14];
  366.   found       : boolean;
  367.  
  368. procedure purge;
  369.  
  370.   begin
  371.     repeat
  372.     until cgetc(1) = -1;
  373.   end;
  374.  
  375. function upper(tstr : wstr) : wstr;
  376.  
  377.   var 
  378.     i : integer;
  379.  
  380.   begin
  381.     for i := 1 to length(tstr) do
  382.       tstr[i] := upcase(tstr[i]);
  383.   end;
  384.  
  385. procedure stat_write(tstr : wstr);
  386.  
  387.   var 
  388.     x,y : integer;
  389.  
  390.   begin
  391.     x := wherex;
  392.     y := wherey;
  393.     textcolor(0);
  394.     textbackground(7);
  395.     window(1,1,80,25);
  396.     gotoxy(1,25);
  397.     clreol;
  398.     write(output,tstr);
  399.     gotoxy(65,25);
  400.     write('Terminal 1.0');
  401.     window(1,1,80,24);
  402.     textcolor(7);
  403.     textbackground(0);
  404.     gotoxy(x,y);
  405.   end;
  406.  
  407. function stat_read(pstr : wstr) : wstr;
  408.  
  409.   var 
  410.     x,y  : integer;
  411.     tstr : wstr;
  412.  
  413.   begin
  414.     x := wherex;
  415.     y := wherey;
  416.     textcolor(0);
  417.     textbackground(7);
  418.     window(1,1,80,25);
  419.     gotoxy(1,25);
  420.     clreol;
  421.     write(output,pstr);
  422.     gotoxy(65,25);
  423.     write('Terminal 1.0');
  424.     gotoxy(length(pstr) + 1,25);
  425.     read(tstr);
  426.     stat_read := tstr;
  427.     window(1,1,80,24);
  428.     textcolor(7);
  429.     textbackground(0);
  430.     gotoxy(x,y);
  431.   end;
  432.  
  433. procedure dial;
  434.  
  435.   var 
  436.     parms,number,tstr : wstr;
  437.     phonefile         : text;
  438.  
  439.     begin
  440.       parms := stat_read('Number to dial? ');
  441.       number := parms;
  442.       stat_write('Dialing ' + number + '....');
  443.       strsend('ATDT' + number + ^M);
  444.       purge;
  445.       repeat
  446.       until
  447.       cgetc(0) <> -1;
  448.       purge;
  449.       if old_carrier
  450.         then
  451.           stat_write('Dialing ' + number + '....Connected')
  452.         else
  453.           stat_write('Dialing ' + number + '....No Carrier');
  454.     end;
  455.  
  456. procedure identify;
  457.  
  458.   begin
  459.     stat_write('Sending Identification...');
  460.     strsend('#IBM PC PCDOS,CC,PA'+^m);
  461.     stat_write('Connected');
  462.   end;
  463.  
  464. procedure protocol;
  465.  
  466.   const 
  467.     ESCAPE = $1B;
  468.     SI     = $0F;
  469.     SO     = $0E;
  470.     SOH    = $01;
  471.     ETX    = $03;
  472.     EOT    = $04;
  473.     ENQ    = $05;
  474.     DLE    = $10;
  475.     A_EOF  = $1A;
  476.     A_ACK  = '.';
  477.     A_NAK  = '/';
  478.     A_ABORT  = $11;
  479.  
  480.   var 
  481.     count : integer;
  482.     recvd : integer;
  483.     done  : boolean;
  484.  
  485.   procedure filetrana;
  486.  
  487.     var 
  488.       recnum   : integer;
  489.       tstr     : wstr;
  490.       size     : wstr;
  491.       checksum : integer;
  492.       areclen  : integer;
  493.       arecord  : buftype;
  494.       status   : integer;
  495.       i        : integer;
  496.  
  497.     function increc(c : integer) : integer;
  498.  
  499.       begin
  500.         if c = ord('9')
  501.           then
  502.             increc := ord('0')
  503.           else
  504.             increc := c + 1;
  505.       end;
  506.  
  507.     function getarecord(var arecord : buftype) : integer;
  508.  
  509.       var 
  510.         retries : integer;
  511.         recvd   : integer;
  512.         gotchk  : integer;
  513.         buffptr : integer;
  514.         line    : bigstring;
  515.         return  : integer;
  516.         stat    : integer;
  517.  
  518.       function getmask : integer;
  519.  
  520.         var 
  521.           ch : integer;
  522.  
  523.         begin
  524.           repeat
  525.             ch := cgetc(0);
  526.           until ch > 0;
  527.           if ch = DLE
  528.             then
  529.               ch := (cgetc(30) and $1F) or 256;
  530.           getmask := ch;
  531.         end;
  532.  
  533.       function getcheck : integer;
  534.  
  535.         var 
  536.           ch : integer;
  537.           c  : integer;
  538.  
  539.         begin
  540.           ch := getmask;
  541.           if ch <> ETX
  542.             then
  543.               begin
  544.                 c := ch and $FF;
  545.                 if (checksum and $80) = 0
  546.                   then
  547.                     checksum := checksum shl 1
  548.                   else
  549.                     checksum := ((checksum shl 1) and $FF) + 1;
  550.                 checksum := checksum + c;
  551.                 if checksum >= $100
  552.                   then
  553.                     checksum := (checksum + 1) and $FF;
  554.               end;
  555.           getcheck := ch;
  556.         end;
  557.  
  558.       begin
  559.         return := 1;
  560.         retries := 1;
  561.         while (retries < 10) and (return = 1) do
  562.           begin
  563.             retries := retries + 1;
  564.             repeat
  565.               stat := cgetc(30);
  566.             until (stat = -1) or (stat = SOH) or ((stat and $7f) = SOH);
  567.             stat := stat and $7f;
  568.             if SOH = stat
  569.               then
  570.                 begin
  571.                   checksum := 0;
  572.                   recvd := getcheck and $7F;
  573.                   if increc(recvd) = recnum
  574.                     then
  575.                       begin
  576.                         stat_write('Invalid record number (off by 1)');
  577.                         purge;
  578.                         send(ord(A_ACK));
  579.                       end
  580.                     else
  581.                       if recvd <> recnum
  582.                         then
  583.                           begin
  584.                             stat_write('Invalid record number: ' + chr(recvd + 48));
  585.                             purge;
  586.                             send(ord(A_NAK));
  587.                           end
  588.                         else
  589.                           begin
  590.                             areclen := 0;
  591.                             buffptr := 0;
  592.                             recvd := getcheck;
  593.                             while ETX <> recvd do
  594.                               begin
  595.                                 arecord[buffptr] := chr(recvd);
  596.                                 buffptr := succ(buffptr);
  597.                                 areclen := succ(areclen);
  598.                                 if (areclen mod 16) = 0
  599.                                   then
  600.                                     begin
  601.                                       tstr := tstr + '.';
  602.                                       stat_write(tstr);
  603.                                     end;
  604.                                 recvd := getcheck;
  605.                               end;
  606.  
  607.                             gotchk := getmask and $FF;
  608.                             if checksum = gotchk
  609.                               then
  610.                                 begin
  611.                                   tstr := '';
  612.                                   recnum := increc(recnum);
  613.                                   return := 0;
  614.                                 end
  615.                               else
  616.                                 begin
  617.                                   stat_write(' NAK');
  618.                                   tstr := copy(tstr,1,12);
  619.                                   stat_write(tstr);
  620.                                   purge;
  621.                                   send(ord(A_NAK));
  622.                                 end;
  623.                           end;
  624.                 end;
  625.           end;
  626.         if return = 1
  627.           then
  628.             begin
  629.               stat_write('Too many retries');
  630.               send(ord(^U));
  631.               getarecord := 1;
  632.             end
  633.           else
  634.             getarecord := 0;
  635.       end;
  636.  
  637.     procedure a_download(var arecord : buftype);
  638.  
  639.       var 
  640.         filename : string[30];
  641.         dowfile  : file of byte;
  642.         i,ch     : integer;
  643.         end_file : byte;
  644.         tint     : integer;
  645.         rply     : char;
  646.         abort    : boolean;
  647.         done     : boolean;
  648.         f_eof    : boolean;
  649.         outbyte  : byte;
  650.  
  651.       begin
  652.         stat_write('File download requested');
  653.         abort := false;
  654.         done  := false;
  655.         i := 2;
  656.         filename := '';
  657.         while arecord[i] <> ^M do
  658.           begin
  659.             filename := filename + arecord[i];
  660.             i := succ(i);
  661.           end;
  662.       {$i-} {turn of io checking}
  663.         assign(dowfile,filename);
  664.         reset(dowfile);
  665.         if ioresult = 0
  666.           then
  667.             begin
  668.               close(dowfile);
  669.               stat_write('The file, "' + filename +
  670.                          '", already exists.  Overwrite it? (y/n)');
  671.               read(kbd,rply);
  672.               abort := not(rply in ['Y','y']);
  673.             end;
  674.  
  675.         if not abort
  676.           then
  677.             begin
  678.               rewrite(dowfile);
  679.               abort := ioresult <> 0;
  680.               if abort
  681.                 then
  682.                   stat_write('Unable to open/create, "' + filename + '"');
  683.             end;
  684.  
  685.         if not abort
  686.           then
  687.             begin
  688.               tstr := 'Receiving file: ' + filename + ' as ';
  689.               if arecord[1] = 'B'
  690.                 then
  691.                   begin
  692.                     end_file := 4;
  693.                     stat_write(tstr + 'a binary file.');
  694.                   end
  695.                 else
  696.                   begin
  697.                     end_file := 26;
  698.                     stat_write(tstr + 'as an ascii file.');
  699.                   end;
  700.               while not done do
  701.                 begin
  702.                   str(longfilesize(dowfile): 6: 0,size);
  703.                   tstr := chr(recnum) + ' (' + size + '):  ';
  704.                   stat_write(tstr);
  705.                   purge;
  706.                   send(ord(A_ACK));
  707.                   if getarecord(arecord) <> 0
  708.                     then
  709.                       begin
  710.                         stat_write('Communications failure!');
  711.                         close(dowfile);
  712.                         done := true;
  713.                       end
  714.                     else
  715.                       begin
  716.                         i := 0;
  717.                         f_eof := i >= areclen;
  718.                         while not f_eof do
  719.                           if ((arecord[i] = chr(EOT)) and (areclen = 1)) or
  720.                              ((arecord[i] = chr(A_EOF)) and (end_file = A_EOF))
  721.                             then
  722.                               begin
  723.                                 f_eof := true;
  724.                                 close(dowfile);
  725.                                 stat_write('download complete.');
  726.                                 purge;
  727.                                 send(ord(A_ACK));
  728.                               end
  729.                             else
  730.                               begin
  731.                                 outbyte := byte(arecord[i]);
  732.                                 write(dowfile,outbyte);
  733.                                 flush(dowfile);
  734.                                 i := succ(i);
  735.                                 f_eof := i >= areclen;
  736.                               end;
  737.                         if i < areclen
  738.                           then
  739.                             done := true;
  740.                       end;
  741.                 end;
  742.             end;
  743.       end;
  744.  
  745.   procedure a_upload;
  746.  
  747.     var 
  748.       filename : string[30];
  749.       upfile   : file of byte;
  750.       i        : integer;
  751.       ch       : byte;
  752.       end_hit,
  753.       abort,
  754.       done     : boolean;
  755.  
  756.     function sendrecord : integer;
  757.  
  758.       var 
  759.         retries : integer;
  760.         acknak  : integer;
  761.         quit    : boolean;
  762.  
  763.       procedure putrecord;
  764.  
  765.         var 
  766.           i : integer;
  767.           checksum : integer;
  768.  
  769.         procedure putmasked(ch : integer);
  770.  
  771.             begin
  772.               if not((areclen = 1) and (ch = eot))
  773.                 then
  774.                   if ch in [$1..$4,$10,$15]
  775.                     then
  776.                       begin
  777.                         send(DLE);
  778.                         send(ch + $40);
  779.                       end
  780.                     else
  781.                       send(ch and $ff)
  782.                 else
  783.                   send(ch and $ff);
  784.             end;
  785.  
  786.         procedure putcheck(ch : integer);
  787.  
  788.           var 
  789.             c : integer;
  790.  
  791.             begin
  792.               c := ch and $ff;
  793.               if (checksum and $80) = 0
  794.                 then
  795.                   checksum := checksum shl 1
  796.                 else
  797.                   checksum := ((checksum shl 1) and $ff) + 1;
  798.               checksum := checksum + c;
  799.               if checksum >= $100
  800.                 then
  801.                   checksum := $ff and (checksum + 1);
  802.               putmasked(ch);
  803.             end;
  804.  
  805.           begin
  806.             send(SOH);
  807.             checksum := 0;
  808.             putcheck(recnum);
  809.             for i := 0 to areclen - 1 do
  810.               begin
  811.                 putcheck(ord(arecord[i]));
  812.                 if (i mod 32) = 0
  813.                   then
  814.                     begin
  815.                       tstr := tstr + '.';
  816.                       stat_write(tstr);
  817.                     end;
  818.               end;
  819.             send(ETX);
  820.             putmasked(checksum);
  821.           end;
  822.  
  823.         begin
  824.           retries := 0;
  825.           quit    := false;
  826.           while (retries < 10) and not(quit) do
  827.             begin
  828.               retries := succ(retries);
  829.               tstr := tstr + chr(recnum);
  830.               stat_write(tstr);
  831.               putrecord;
  832.               acknak := cgetc(10);
  833.               if acknak = ord(A_ACK)
  834.                 then
  835.                   begin
  836.                     recnum := increc(recnum);
  837.                     quit := true;
  838.                     sendrecord := 0;
  839.                   end
  840.                 else if acknak = A_ABORT
  841.                        then
  842.                          begin
  843.                            stat_write('Abort!');
  844.                            sendrecord := 1;
  845.                            quit := true;
  846.                          end
  847.                        else if acknak = ord(A_NAK)
  848.                               then
  849.                                 begin
  850.                                   stat_write('NAK: ' + chr(acknak));
  851.                                   tstr := copy(tstr,1,14);
  852.                                   stat_write(tstr);
  853.                                   quit := false;
  854.                                 end;
  855.             end;
  856.  
  857.           if acknak = ord(A_NAK)
  858.             then
  859.               begin
  860.                 send(A_ABORT);
  861.                 stat_write('Too many retries!');
  862.                 sendrecord := 1;
  863.               end;
  864.         end;
  865.  
  866.       begin
  867.         tstr := 'Preparing to upload "';
  868.         i := 2;
  869.         filename := '';
  870.         while arecord[i] <> ^M do
  871.           begin
  872.             filename := filename + arecord[i];
  873.             i := succ(i);
  874.           end;
  875.         stat_write(tstr + filename + '".');
  876.       {$i-} {turn of io checking}
  877.         assign(upfile,filename);
  878.         reset(upfile);
  879.         if ioresult = 0
  880.           then
  881.             begin
  882.               str(longfilesize(upfile): 0: 0,tstr);
  883.               stat_write('"' + filename + '" is ' + tstr + ' bytes long.');
  884.               send(ord(A_ACK));
  885.               repeat
  886.               until ord(A_ACK) = cgetc(10);
  887.               repeat
  888.                 tstr := '';
  889.                 areclen := 0;
  890.                 str(longfilepos(upfile)/longfilesize(upfile)*100: 5: 1,size);
  891.                 tstr := size + '% (';
  892.                 str(longfilepos(upfile): 7: 0,size);
  893.                 tstr := tstr + size + ') -- ';
  894.                 stat_write(tstr);
  895.                 repeat
  896.                   read(upfile,ch);
  897.                   arecord[areclen] := chr(ch);
  898.                   areclen := areclen + 1;
  899.                 until eof(upfile) or (areclen > 256);
  900.  
  901.                 if sendrecord <> 0
  902.                   then
  903.                     begin
  904.                       abort := true;
  905.                       close(upfile);
  906.                       stat_write('Communications failure !');
  907.                     end
  908.                   else
  909.                     abort := false;
  910.               until abort or eof(upfile);
  911.  
  912.               if not abort
  913.                 then
  914.                   begin
  915.                     tstr := '';
  916.                     arecord[0] := chr(EOT);
  917.                     areclen := 1;
  918.                     str(longfilepos(upfile)/longfilesize(upfile)*100: 5: 1,size);
  919.                     tstr := size + '% (';
  920.                     str(longfilepos(upfile): 7: 0,size);
  921.                     tstr := tstr + size + ') -- ';
  922.                     stat_write(tstr);
  923.                     ch := sendrecord;
  924.                     close(upfile);
  925.                   end;
  926.             end
  927.           else
  928.             begin
  929.               stat_write('Cannot open "' + filename + '".');
  930.               send(A_ABORT);
  931.             end;
  932.       end;
  933.  
  934.     begin
  935.       stat_write('File transfer requested');
  936.       recnum := ord('1');
  937.       repeat
  938.         status := getarecord(arecord);
  939.       until (status = 0) or keypressed;
  940.       if status = 0
  941.         then
  942.           case arecord[0] of
  943.             'U' : a_upload;
  944.             'D' : a_download(arecord);
  945.           end;
  946.     end;
  947.  
  948.  
  949.   begin
  950.     done := false;
  951.     repeat
  952.       recvd := cgetc(10);
  953.       if recvd > 0
  954.         then
  955.           begin
  956.             recvd := recvd and $7F;
  957.             while (recvd = SI) or (recvd = -1) do
  958.               recvd := cgetc(1);
  959.             if recvd <> SO
  960.               then
  961.                 begin
  962.                   if recvd = ESCAPE
  963.                     then
  964.                       repeat
  965.                         recvd := cgetc(0) and $7F;
  966.                         case char(recvd) of
  967.                           'I' : identify;
  968.                           'A' : filetrana;
  969.                           'G' : {graphics;}
  970.                         end;
  971.                       until recvd in [65,71,73,SO]
  972.                     else
  973.                       done := true;
  974.                   recvd := cgetc(1);
  975.                 end
  976.           end
  977.         else
  978.           done := true;
  979.       done := done or keypressed or (recvd = SO);
  980.     until done;
  981.     stat_write('Connected');
  982.   end;
  983.  
  984. procedure escape;
  985.  
  986.   var
  987.     rcvd : integer;
  988.     ch   : char;
  989.     x,y  : integer;
  990.  
  991.   begin
  992.     rcvd := cgetc(1);
  993.     if rcvd > 0
  994.       then
  995.         case rcvd of
  996.           89 : begin
  997.                  y := cgetc(1) - 31;
  998.                  x := cgetc(1) - 31;
  999.                  gotoxy(x,y);
  1000.                end;
  1001.           65 : gotoxy(wherex,wherey - 1);
  1002.           66 : gotoxy(wherex,wherey + 1);
  1003.           67 : gotoxy(wherex + 1,wherey);
  1004.           68 : gotoxy(wherex - 1,wherey);
  1005.           71 : {graphics};
  1006.           72 : gotoxy(1,1);
  1007.           73 : identify;
  1008.           75 : clreol;
  1009.           74 : begin
  1010.                  clreol;
  1011.                  for y := wherey + 1 to 25 do
  1012.                    begin
  1013.                      gotoxy(1,y);
  1014.                      clreol;
  1015.                    end;
  1016.                end;
  1017.           106 : clrscr;
  1018.         end;
  1019.   end;
  1020.  
  1021. {$u-}
  1022. begin {terminal}
  1023.   ClrScr;
  1024.   stat_write('Initializing');
  1025.   buffptr := minint;
  1026.   save := false;
  1027.   left1 := false;
  1028.   left4 := false;
  1029.   left256 := false;
  1030.   new(buffer);
  1031.   set_up_recv_buffer;
  1032.   setup;
  1033.   exit   := false;
  1034.   stat_write('Ready');
  1035.   old_carrier := false;
  1036.  
  1037.   repeat
  1038.     if old_carrier xor carrier
  1039.       then
  1040.         begin
  1041.           old_carrier := carrier;
  1042.           if old_carrier
  1043.             then
  1044.               stat_write('Connected')
  1045.             else
  1046.               stat_write('No Carrier');
  1047.         end;
  1048.  
  1049.     if keypressed
  1050.       then
  1051.         begin
  1052.           read(kbd,ch);
  1053.           if ch = ^[
  1054.             then
  1055.               begin
  1056.                 read(kbd,ch);
  1057.                 case ord(ch) of
  1058.                   32 : dial;
  1059.                   25 : begin
  1060.                          parms := stat_read('Set parameter (parameter,value) ?');
  1061.                          i := 1;
  1062.                          while i <= length(parms) do
  1063.                            begin
  1064.                              case parms[i] of
  1065.                                'f','F' : begin
  1066.                                            filename := copy(parms,pos(',',parms) + 1,
  1067.                                                        length(parms) - pos(',',parms));
  1068.                                            i := length(parms) + 1;
  1069.                                          end;
  1070.                                'b','B' : begin
  1071.                                            i := length(parms) + 1;
  1072.                                            tstr := copy(parms,pos(',',parms) + 1,
  1073.                                                    length(parms) - pos(',',parms));
  1074.                                            parms := '';
  1075.                                            for i := 1 to length(tstr) do
  1076.                                              if tstr[i] in ['0'..'9']
  1077.                                                then
  1078.                                                  parms := parms + tstr[i];
  1079.                                            val(parms,j,i);
  1080.                                            if i = 0
  1081.                                              then
  1082.                                                speed := j;
  1083.                                            stat_write('New Baud Rate: ' + parms);
  1084.                                            init_port;
  1085.                                            delay(2000)
  1086.                                          end;
  1087.                                'p','P' : begin
  1088.                                            i := length(parms) + 1;
  1089.                                            tstr := copy(parms,pos(',',parms) + 1,
  1090.                                                    length(parms) - pos(',',parms));
  1091.                                            j := 1;
  1092.                                            while j <= length(tstr) do
  1093.                                              case tstr[j] of
  1094.                                                'e','E' : begin
  1095.                                                            parity := even;
  1096.                                                            j := length(tstr) + 1
  1097.                                                          end;
  1098.                                                'n','N' : begin
  1099.                                                            parity := none;
  1100.                                                            j := length(tstr) + 1;
  1101.                                                          end
  1102.                                                else
  1103.                                                  j := j + 1;
  1104.                                              end;
  1105.                                            stat_write('New parity: '+ tstr);
  1106.                                            init_port;
  1107.                                            delay(2000);
  1108.                                          end;
  1109.                                's','S' : begin
  1110.                                            tstr := copy(parms,pos(',',parms) + 1,
  1111.                                                    length(parms) - pos(',',parms));
  1112.                                            parms := '';
  1113.                                            for i := 1 to length(tstr) do
  1114.                                              if tstr[i] in ['1','2']
  1115.                                                then
  1116.                                                  parms := tstr[i];
  1117.                                            val(parms,j,i);
  1118.                                            if i = 0
  1119.                                              then
  1120.                                                stop_bits := j;
  1121.                                            stat_write('New Stop Bits: ' + parms);
  1122.                                            init_port;
  1123.                                            delay(2000)
  1124.                                          end;
  1125.  
  1126.                                'w','W' : begin
  1127.                                            tstr := copy(parms,pos(',',parms) + 1,
  1128.                                                    length(parms) - pos(',',parms));
  1129.                                            parms := '';
  1130.                                            for i := 1 to length(tstr) do
  1131.                                              if tstr[i] in ['7','8']
  1132.                                                then
  1133.                                                  parms := tstr[i];
  1134.                                            val(parms,j,i);
  1135.                                            if i = 0
  1136.                                              then
  1137.                                                dbits := j;
  1138.                                            stat_write('New Data Bits: ' + parms);
  1139.                                            init_port;
  1140.                                            delay(2000)
  1141.                                          end;
  1142.  
  1143.                                'd','D' : begin
  1144.                                            tstr := 'Current: ';
  1145.                                            str(speed,parms);
  1146.                                            tstr := tstr + parms + ' baud, ';
  1147.                                            str(dbits,parms);
  1148.                                            tstr := tstr + parms + ' data bits, ';
  1149.                                            str(stop_bits,parms);
  1150.                                            tstr := tstr + parms + ' stop bits, ';
  1151.                                            if parity = none
  1152.                                              then
  1153.                                                tstr := tstr + 'no parity';
  1154.                                            if parity = even
  1155.                                              then
  1156.                                                tstr := tstr + 'even parity';
  1157.                                            stat_write(tstr);
  1158.                                            delay(2000);
  1159.                                          end;
  1160.  
  1161.                              else
  1162.                                i := i + 1;
  1163.                            end;
  1164.                        end;
  1165.                   if old_carrier
  1166.                     then
  1167.                       stat_write('Connected')
  1168.                     else
  1169.                       stat_write('No Carrier');
  1170.                 end;
  1171.                 31 : begin
  1172.                        save := true;
  1173.                        stat_write('Capture buffer on');
  1174.                        delay(100);
  1175.                        if old_carrier
  1176.                          then
  1177.                            stat_write('Connected')
  1178.                          else
  1179.                            stat_write('No Carrier');
  1180.                      end;
  1181.                 46 : begin
  1182.                        save := false;
  1183.                        stat_write('Capture buffer off');
  1184.                        delay(100);
  1185.                        if old_carrier
  1186.                          then
  1187.                            stat_write('Connected')
  1188.                          else
  1189.                            stat_write('No Carrier');
  1190.                      end;
  1191.                 17 : begin
  1192.                        stat_write('Saving capture buffer to "' + filename + '"');
  1193.                        assign(capture,filename);
  1194.                {$i-}
  1195.                        reset(capture);
  1196.                        if ioresult = 0
  1197.                          then
  1198.                            longseek(capture,longfilesize(capture))
  1199.                          else
  1200.                            rewrite(capture);
  1201.                        blockwrite(capture,buffer^,((buffptr + 32767) div 128) + 2);
  1202.                        str((((buffptr + 32767) div 128) + 1): 5,tstr);
  1203.                        stat_write(tstr);
  1204.                        delay(2000);
  1205.                        close(capture);
  1206.                        buffptr := minint;
  1207.                        if old_carrier
  1208.                          then
  1209.                            stat_write('Connected')
  1210.                          else
  1211.                            stat_write('No Carrier');
  1212.                      end;
  1213.                 37 : begin
  1214.                        stat_write('Clearing capture buffer');
  1215.                        delay(100);
  1216.                        buffptr := minint;
  1217.                        left4 := false;
  1218.                        left1 := false;
  1219.                        left256 := false;
  1220.                        if old_carrier
  1221.                          then
  1222.                            stat_write('Connected')
  1223.                          else
  1224.                            stat_write('No Carrier');
  1225.                      end;
  1226.                 45 : begin
  1227.                        exit := true;
  1228.                        stat_write('Exiting...');
  1229.                      end;
  1230.                 35 : begin
  1231.                        term_ready(false);
  1232.                        delay(10);
  1233.                        stat_write('Disconnecting...');
  1234.                        term_ready(true);
  1235.                      end;
  1236.               end;
  1237.         end
  1238.       else
  1239.         send(ord(ch));
  1240.       end;
  1241.  
  1242.     if not exit
  1243.       then
  1244.         begin
  1245.  
  1246.           rcvd := cgetc(0);
  1247.  
  1248.           if save and (rcvd > 0)
  1249.             then
  1250.               begin
  1251.                 if (buffptr > (maxint - 4096)) and not left4
  1252.                   then
  1253.                     begin
  1254.                       left4 := true;
  1255.                       stat_write('Only 4k left in capture buffer');
  1256.                     end;
  1257.                 if (buffptr > (maxint - 1024)) and not left1
  1258.                   then
  1259.                     begin
  1260.                       left1 := true;
  1261.                       stat_write('Only 1k left in capture buffer');
  1262.                     end;
  1263.                 if (buffptr > (maxint - 256)) and not left256
  1264.                   then
  1265.                     begin
  1266.                       left256 := true;
  1267.                       stat_write('Only 256 bytes left in capture buffer');
  1268.                     end;
  1269.                 if buffptr = maxint
  1270.                   then
  1271.                     begin
  1272.                       stat_write('Capture buffer closed.');
  1273.                       save := false;
  1274.                     end
  1275.                   else
  1276.                     begin
  1277.                       buffer^[buffptr] := rcvd and $7f;
  1278.                       buffptr := succ(buffptr);
  1279.                     end;
  1280.               end;
  1281.  
  1282.           if rcvd > 0
  1283.             then
  1284.               case rcvd of
  1285.                 15      : protocol;
  1286.                 14      : ;
  1287.                 12      : clrscr;
  1288.                 13      : write(^M);
  1289.                 10      : write(^J);
  1290.                 8      : write(^h,' ',^h);
  1291.                 27      : escape;
  1292.                 32..255 : write(chr(rcvd and $7F));
  1293.               end;
  1294.         end;
  1295.  
  1296.   until exit;
  1297.   dispose(buffer);
  1298.   remove_port;
  1299.   textbackground(0);
  1300.   textcolor(7);
  1301. end.
  1302.